#include "CTcpSocket.h"
#include "CTcpSocketImpl.h"
#include "CNetService.h"

namespace TB
{
    CTcpSocket::CTcpSocket(int nSocketFD)
    {
        m_poImpl = std::make_shared<CTcpSocketImpl>(nSocketFD);
    }

	CTcpSocket::CTcpSocket()
	{
        m_poImpl = std::make_shared<CTcpSocketImpl>();
	}

	CTcpSocket::~CTcpSocket()
	{
		Close();
	}

    const std::weak_ptr<CNetService>& CTcpSocket::GetNetService() const
    {
        return m_poImpl->GetNetService();
    }

	bool CTcpSocket::Init(const std::weak_ptr<CNetService>& poNetService)
	{
        return m_poImpl->Init(poNetService, m_poImpl);
	}

    ENetErrorCode CTcpSocket::Bind(UINT32 dwIp, UINT16 wPort)
    {
        return m_poImpl->Bind(dwIp, wPort);
    }

    bool CTcpSocket::GetLocalIpPort(std::pair<UINT32, UINT16>& roIpPort) const //主机字节序
	{
        return m_poImpl->GetLocalIpPort(roIpPort);
	}

	bool CTcpSocket::IsClosed() const
	{
        return m_poImpl->IsClosed();
	}

    bool CTcpSocket::IsConnecting() const
    {
        return m_poImpl->IsConnecting();
    }

    bool CTcpSocket::IsConnected() const
    {
        return m_poImpl->IsConnected();
    }

    bool CTcpSocket::GetRemoteIpPort(std::pair<UINT32, UINT16>& roIpPort) const
    {
        return m_poImpl->GetRemoteIpPort(roIpPort);
    }

    bool CTcpSocket::SetNoDelay(bool bNoDelay)
    {
        return m_poImpl->SetNoDelay(bNoDelay);
    }

    bool CTcpSocket::SetSendBuffer(UINT32 dwSize)
    {
        return m_poImpl->SetSendBuffer(dwSize);
    }

    bool CTcpSocket::SetRecvBuffer(UINT32 dwSize)
    {
        return m_poImpl->SetRecvBuffer(dwSize);
    }

	void CTcpSocket::Close()
	{
        if (IsClosed())
            return;
        auto poNetService = m_poImpl->GetNetService().lock();
        auto poCoroutine = !poNetService ? nullptr : poNetService->GetCoroutine().lock();
        if (poCoroutine == nullptr || CCoroutine::GetCurrent() == poCoroutine)
        {
            m_poImpl->Close();
        }
        else
        {
            std::shared_ptr<CTcpSocketImpl> poImpl = m_poImpl;
            poCoroutine->Post([poImpl]() mutable
            {
                poImpl->Close();
            });
        }
	}

    STask<ENetErrorCode> CTcpSocket::Connect(UINT32 dwIp, UINT16 wPort, UINT64 qwTimeoutMilliSeconds)
    {
        auto sTaskProcessor = CTaskHelper::CreatePendingTask<ENetErrorCode>();
        auto poNetService = m_poImpl->GetNetService().lock();
        if (!poNetService)
            return CTaskHelper::Resolve(ENetErrorCode::OperationAborted);
        auto poCoroutine = poNetService->GetCoroutine().lock();
        if (!poCoroutine)
            return CTaskHelper::Resolve(ENetErrorCode::OperationAborted);
        if (CCoroutine::GetCurrent() == poCoroutine)
        {
            m_poImpl->Connect(dwIp, wPort, qwTimeoutMilliSeconds, sTaskProcessor);
        }
        else
        {
            std::weak_ptr<CTcpSocketImpl> poWeakPtr = m_poImpl;
            poCoroutine->Post([sTaskProcessor, poWeakPtr, dwIp, wPort, qwTimeoutMilliSeconds]() mutable
            {
                auto poImpl = poWeakPtr.lock();
                if (poImpl == nullptr)
                {
                    sTaskProcessor.Resolve(ENetErrorCode::OperationAborted);
                    return;
                }
                poImpl->Connect(dwIp, wPort, qwTimeoutMilliSeconds, sTaskProcessor);
            });
        }
        return sTaskProcessor.GetTask();
    }

    STask<ENetErrorCode> CTcpSocket::Send(const std::pair<UINT8*, UINT32>& sBuffer)
    {
        auto sTaskProcessor = CTaskHelper::CreatePendingTask<ENetErrorCode>();
        auto poNetService = m_poImpl->GetNetService().lock();
        if (!poNetService)
            return CTaskHelper::Resolve(ENetErrorCode::OperationAborted);
        auto poCoroutine = poNetService->GetCoroutine().lock();
        if (!poCoroutine)
            return CTaskHelper::Resolve(ENetErrorCode::OperationAborted);
        if (CCoroutine::GetCurrent() == poCoroutine)
        {
            m_poImpl->Send(sBuffer, sTaskProcessor);
        }
        else
        {
            std::weak_ptr<CTcpSocketImpl> poWeakPtr = m_poImpl;
            poCoroutine->Post([sTaskProcessor, poWeakPtr, sBuffer]() mutable
            {
                auto poImpl = poWeakPtr.lock();
                if (poImpl == nullptr)
                {
                    sTaskProcessor.Resolve(ENetErrorCode::OperationAborted);
                    return;
                }
                poImpl->Send(sBuffer, sTaskProcessor);
            });
        }
        return sTaskProcessor.GetTask();
    }

    STask<ENetErrorCode> CTcpSocket::Send(const std::pair<UINT8*, UINT32>& sBuffer1, const std::pair<UINT8*, UINT32>& sBuffer2)
    {
        auto sTaskProcessor = CTaskHelper::CreatePendingTask<ENetErrorCode>();
        auto poNetService = m_poImpl->GetNetService().lock();
        if (!poNetService)
            return CTaskHelper::Resolve(ENetErrorCode::OperationAborted);
        auto poCoroutine = poNetService->GetCoroutine().lock();
        if (!poCoroutine)
            return CTaskHelper::Resolve(ENetErrorCode::OperationAborted);
        if (CCoroutine::GetCurrent() == poCoroutine)
        {
            m_poImpl->Send(sBuffer1, sBuffer2, sTaskProcessor);
        }
        else
        {
            std::weak_ptr<CTcpSocketImpl> poWeakPtr = m_poImpl;
            poCoroutine->Post([sTaskProcessor, poWeakPtr, sBuffer1, sBuffer2]() mutable
            {
                auto poImpl = poWeakPtr.lock();
                if (poImpl == nullptr)
                {
                    sTaskProcessor.Resolve(ENetErrorCode::OperationAborted);
                    return;
                }
                poImpl->Send(sBuffer1, sBuffer2, sTaskProcessor);
            });
        }
        return sTaskProcessor.GetTask();
    }

    STask<ENetErrorCode> CTcpSocket::Send(const std::pair<UINT8*, UINT32>& sBuffer1, const std::pair<UINT8*, UINT32>& sBuffer2, const std::pair<UINT8*, UINT32>& sBuffer3)
    {
        auto sTaskProcessor = CTaskHelper::CreatePendingTask<ENetErrorCode>();
        auto poNetService = m_poImpl->GetNetService().lock();
        if (!poNetService)
            return CTaskHelper::Resolve(ENetErrorCode::OperationAborted);
        auto poCoroutine = poNetService->GetCoroutine().lock();
        if (!poCoroutine)
            return CTaskHelper::Resolve(ENetErrorCode::OperationAborted);
        if (CCoroutine::GetCurrent() == poCoroutine)
        {
            m_poImpl->Send(sBuffer1, sBuffer2, sBuffer3, sTaskProcessor);
        }
        else
        {
            std::weak_ptr<CTcpSocketImpl> poWeakPtr = m_poImpl;
            poCoroutine->Post([sTaskProcessor, poWeakPtr, sBuffer1, sBuffer2, sBuffer3]() mutable
            {
                auto poImpl = poWeakPtr.lock();
                if (poImpl == nullptr)
                {
                    sTaskProcessor.Resolve(ENetErrorCode::OperationAborted);
                    return;
                }
                poImpl->Send(sBuffer1, sBuffer2, sBuffer3, sTaskProcessor);
            });
        }
        return sTaskProcessor.GetTask();
    }

    STask<ENetErrorCode> CTcpSocket::Send(const std::pair<UINT8*, UINT32>* psBuffers, UINT32 dwCount)
    {
        auto sTaskProcessor = CTaskHelper::CreatePendingTask<ENetErrorCode>();
        auto poNetService = m_poImpl->GetNetService().lock();
        if (!poNetService)
            return CTaskHelper::Resolve(ENetErrorCode::OperationAborted);
        auto poCoroutine = poNetService->GetCoroutine().lock();
        if (!poCoroutine)
            return CTaskHelper::Resolve(ENetErrorCode::OperationAborted);
        if (CCoroutine::GetCurrent() == poCoroutine)
        {
            m_poImpl->Send(psBuffers, dwCount, sTaskProcessor);
        }
        else
        {
            std::weak_ptr<CTcpSocketImpl> poWeakPtr = m_poImpl;
            poCoroutine->Post([sTaskProcessor, poWeakPtr, psBuffers, dwCount]() mutable
            {
                auto poImpl = poWeakPtr.lock();
                if (poImpl == nullptr)
                {
                    sTaskProcessor.Resolve(ENetErrorCode::OperationAborted);
                    return;
                }
                poImpl->Send(psBuffers, dwCount, sTaskProcessor);
            });
        }
        return sTaskProcessor.GetTask();
    }

    STask<std::pair<ENetErrorCode, UINT32>> CTcpSocket::Recv(const std::pair<UINT8*, UINT32>& sBuffer)
    {
        auto sTaskProcessor = CTaskHelper::CreatePendingTask<std::pair<ENetErrorCode, UINT32>>();
        auto poNetService = m_poImpl->GetNetService().lock();
        if (!poNetService)
            return CTaskHelper::Resolve<std::pair<ENetErrorCode, UINT32>>({ ENetErrorCode::OperationAborted, 0 });
        auto poCoroutine = poNetService->GetCoroutine().lock();
        if (!poCoroutine)
            return CTaskHelper::Resolve<std::pair<ENetErrorCode, UINT32>>({ ENetErrorCode::OperationAborted, 0 });
        if (CCoroutine::GetCurrent() == poCoroutine)
        {
            m_poImpl->Recv(sBuffer, sTaskProcessor);
        }
        else
        {
            std::weak_ptr<CTcpSocketImpl> poWeakPtr = m_poImpl;
            poCoroutine->Post([sTaskProcessor, poWeakPtr, sBuffer]() mutable
            {
                auto poImpl = poWeakPtr.lock();
                if (poImpl == nullptr)
                {
                    sTaskProcessor.Resolve({ ENetErrorCode::OperationAborted, 0 });
                    return;
                }
                poImpl->Recv(sBuffer, sTaskProcessor);
            });
        }
        return sTaskProcessor.GetTask();
    }

    STask<std::pair<ENetErrorCode, UINT32>> CTcpSocket::RecvSome(const std::pair<UINT8*, UINT32>& sBuffer)
    {
        auto sTaskProcessor = CTaskHelper::CreatePendingTask<std::pair<ENetErrorCode, UINT32>>();
        auto poNetService = m_poImpl->GetNetService().lock();
        if (!poNetService)
            return CTaskHelper::Resolve<std::pair<ENetErrorCode, UINT32>>({ ENetErrorCode::OperationAborted, 0 });
        auto poCoroutine = poNetService->GetCoroutine().lock();
        if (!poCoroutine)
            return CTaskHelper::Resolve<std::pair<ENetErrorCode, UINT32>>({ ENetErrorCode::OperationAborted, 0 });
        if (CCoroutine::GetCurrent() == poCoroutine)
        {
            m_poImpl->RecvSome(sBuffer, sTaskProcessor);
        }
        else
        {
            std::weak_ptr<CTcpSocketImpl> poWeakPtr = m_poImpl;
            poCoroutine->Post([sTaskProcessor, poWeakPtr, sBuffer]() mutable
            {
                auto poImpl = poWeakPtr.lock();
                if (poImpl == nullptr)
                {
                    sTaskProcessor.Resolve({ ENetErrorCode::OperationAborted, 0 });
                    return;
                }
                poImpl->RecvSome(sBuffer, sTaskProcessor);
            });
        }
        return sTaskProcessor.GetTask();
    }
}